package com.zz.generator;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.config.*;
import com.baomidou.mybatisplus.generator.config.builder.*;
import com.zz.generator.enums.FileType;
import com.zz.generator.util.TableCodeGeneratorUtil;
import org.apache.commons.lang3.StringUtils;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;

import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;

/**
 * @goal genBaseCode
 */
public class GenBaseCodeMojo extends AbstractMojo {

    private static Properties properties = new Properties();
    private static InputStream in = null;
    private static String projectPath = System.getProperty("user.dir");
    private static String SWAGGER_HIDDEN_FIELDS = "createBy,updateBy,expand1,expand2,expand3,expand4,expand5";

    /**
     * 数据源配置
     */
    private static final DataSourceConfig DATA_SOURCE_CONFIG = new DataSourceConfig
            .Builder(getProperty("jdbc.url"), getProperty("jdbc.user"), getProperty("jdbc.password"))
            .driverClassName(getProperty("jdbc.driverClassName"))
            .build();

    public void execute() throws MojoExecutionException, MojoFailureException {
        AutoGenerator generator = new AutoGenerator(DATA_SOURCE_CONFIG);
        // 包配置
        generator.packageInfo(packageConfig().build());
        // 策略配置
//        generator.strategy(tempStrategyConfig().build());
        generator.strategy(strategyConfig().build());
        // 注入配置
        generator.injection(injectionConfig().build());
        // 全局配置
        generator.global(globalConfig().build());
        // 执行
        generator.execute();
    }

    /**
     * 包配置
     */
    protected static PackageConfig.Builder packageConfig() {
        PackageConfig.Builder builder = new PackageConfig.Builder();
        // 配置父级模块名
        builder.moduleName(getProperty("gen.moduleName"));
        // 父级模块名如果为空，下面子包名必须写全部，否则就只需写子包名
        builder.parent(getProperty("gen.parentPackage"));
        return builder;
    }

    protected static StrategyConfig.Builder tempStrategyConfig() {
        StrategyConfig.Builder builder = new StrategyConfig.Builder();
        Mapper.Builder mapperBuilder = builder.mapperBuilder()
                .superClass(BaseMapper.class)
                .enableBaseResultMap()
                .enableBaseColumnList();
        builder.addInclude(getProperty("gen.tableName"));
        return builder;
    }

    /**
     * 策略配置
     */
    protected static StrategyConfig.Builder strategyConfig() {
        StrategyConfig.Builder builder = new StrategyConfig.Builder();

        builder.addTablePrefix(getProperty("gen.prefix"));
        builder.addTableSuffix(getProperty("gen.suffix"));

        builder.entityBuilder().disable();
        builder.controllerBuilder().disable();
        builder.serviceBuilder().disable();
        builder.mapperBuilder().disable();
        builder.addInclude(getProperty("gen.tableName"));
        return builder;
    }

    /**
     * 全局配置
     */
    protected static GlobalConfig.Builder globalConfig() {
        GlobalConfig.Builder builder = new GlobalConfig.Builder();
        builder.outputDir(projectPath + "/src/main/java");
        builder.author(getProperty("gen.author"));
        builder.disableOpenDir();
        builder.commentDate("yyyy-MM-dd HH:mm:ss");
        return builder;
    }

    /**
     * 注入配置
     */
    protected static InjectionConfig.Builder injectionConfig() {
        InjectionConfig.Builder builder = new InjectionConfig.Builder();
        Map<String, Object> customMap = getCustomMap(); // 自定义配置
        List<CustomFile> customFiles = buildCustomFiles(); // 集中构建文件列表
        return builder.customMap(customMap).customFile(customFiles);
    }

    /**
     * 自定义配置
     */
    private static Map<String, Object> getCustomMap() {
        Map<String, Object> customMap = new HashMap<>();
        // 注释时间格式定义
        customMap.put("datetime", LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
        // 开启swagger注解
        customMap.put("enableSwagger", !StringUtils.isNotBlank(getProperty("gen.swagger.enable")) || Boolean.parseBoolean(getProperty("gen.swagger.enable")));
        // swagger-hidden的字段
        customMap.put("swaggerHiddenFields", SWAGGER_HIDDEN_FIELDS);
        // 开启lombok注解
        customMap.put("enableLombok", !StringUtils.isNotBlank(getProperty("gen.lombok.enable")) || Boolean.parseBoolean(getProperty("gen.lombok.enable")));
        // 开启链式编程
        customMap.put("enableChain", StringUtils.isNotBlank(getProperty("gen.chain.enable")) && Boolean.parseBoolean(getProperty("gen.chain.enable")));
        // 父级模块名
        customMap.put("parentPackage", getProperty("gen.parentPackage"));
        // 模块名
        customMap.put("moduleName", getProperty("gen.moduleName"));
        // 中横线模块名
        customMap.put("hyphenModuleName", TableCodeGeneratorUtil.camelToHyphen(getProperty("gen.moduleName")));
        // 方法名
        customMap.put("method", getProperty("gen.method"));

        String prefix = getProperty("gen.prefix");
        String suffix = getProperty("gen.suffix");

        boolean hasPrefix = StringUtils.isNotBlank(prefix);
        boolean hasSuffix = StringUtils.isNotBlank(suffix);

        String entity;

        if (hasPrefix && hasSuffix) {
            entity = TableCodeGeneratorUtil.generateEntityName(getProperty("gen.tableName"), prefix, suffix);
        } else if (hasPrefix) {
            entity = TableCodeGeneratorUtil.generateEntityNameWithPrefix(getProperty("gen.tableName"), prefix);
        } else if (hasSuffix) {
            entity = TableCodeGeneratorUtil.generateEntityNameWithSuffix(getProperty("gen.tableName"), suffix);
        } else {
            entity = TableCodeGeneratorUtil.generateEntityName(getProperty("gen.tableName"));
        }

        customMap.put("entity", entity);
        customMap.put("entityName", TableCodeGeneratorUtil.uncapitalizeFirstLetter(entity));
        customMap.put("hyphenEntity", TableCodeGeneratorUtil.camelToHyphen(entity));
        customMap.forEach((k, v) -> System.out.println(k + " = " + v));
        return customMap;
    }

    /**
     * 构建自定义文件列表（支持灵活扩展）
     */
    private static List<CustomFile> buildCustomFiles() {
        List<CustomFile> files = new ArrayList<>();
        String baseTemplatePath = "/templates/";
        String outputBasePath = projectPath + "/src/main/java/"
                + getProperty("gen.parentPackage").replace(".", "/") + "/"
                + getProperty("gen.moduleName") + "/";

        // 模板路径与生成路径映射（可扩展）
        Map<FileType, String> templateMap = Map.of(
                FileType.CONTROLLER, baseTemplatePath + "controller.java.vm",
                FileType.SERVICE, baseTemplatePath + "service.java.vm",
                FileType.SERVICE_IMPL, baseTemplatePath + "serviceImpl.java.vm",
                FileType.MAPPER, baseTemplatePath + "mapper.java.vm",
                FileType.MAPPER_XML, baseTemplatePath + "mapper.xml.vm",
                FileType.DTO, baseTemplatePath + "dto.java.vm",
                FileType.ENTITY, baseTemplatePath + "entity.java.vm"
        );

        // 文件生成规则配置
        Map<FileType, Boolean> generateMap = Map.of(
                FileType.CONTROLLER, !"true".equals(getProperty("gen.file.only.dto")),
                FileType.SERVICE, !"true".equals(getProperty("gen.file.only.dto")),
                FileType.SERVICE_IMPL, !"true".equals(getProperty("gen.file.only.dto")),
                FileType.MAPPER, !"true".equals(getProperty("gen.file.only.dto")),
                FileType.MAPPER_XML, !"true".equals(getProperty("gen.file.only.dto")),
                FileType.DTO, true,
                FileType.ENTITY, true
        );

        // 动态生成文件列表
        for (Map.Entry<FileType, Boolean> entry : generateMap.entrySet()) {
            if (!entry.getValue()) continue; // 跳过不生成的文件类型
            System.out.println("生成文件：" + entry.getKey());
            String templatePath = templateMap.get(entry.getKey());
            String outputPath = outputBasePath + getOutputDirectoryName(entry.getKey());
            CustomFile.Builder builder = new CustomFile.Builder();
            // 配置覆盖策略
            boolean override = Boolean.parseBoolean(getProperty("gen.file.override"));
            if (override) {
                builder.enableFileOverride();
            }
            files.add(builder
                    .fileName(getFileName(entry.getKey()))
                    .filePath(outputPath)
                    .templatePath(templatePath)
                    .build());
        }

        return files;
    }

    /**
     * 根据文件类型获取生成的文件名（带扩展名）
     */
    private static String getFileName(FileType fileType) {
        return switch (fileType) {
            case CONTROLLER -> "Controller.java";
            case SERVICE -> "Service.java";
            case SERVICE_IMPL -> "ServiceImpl.java";
            case MAPPER -> "Mapper.java";
            case MAPPER_XML -> "Mapper.xml";
            case DTO -> "Dto.java";
            case ENTITY -> ".java";
            default -> throw new IllegalArgumentException("Unknown file type: " + fileType);
        };
    }

    /**
     * 根据文件类型获取输出目录名
     */
    private static String getOutputDirectoryName(FileType fileType) {
        return switch (fileType) {
            case CONTROLLER -> "controller";
            case SERVICE -> "service";
            case SERVICE_IMPL -> "service/impl";
            case MAPPER, MAPPER_XML -> "mapper";
            case DTO -> "dto";
            case ENTITY -> "entity";
            default -> throw new IllegalArgumentException("Unsupported file type: " + fileType);
        };
    }

    /**
     * 获取配置文件信息
     */
    private static String getProperty(String key) {
        // 使用properties对象加载输入流
        try {
            if (in == null) {
                in = Files.newInputStream(Paths.get(projectPath + "/src/main/resources/conf/generator-config.properties"));
            }
            properties.load(in);
        } catch (IOException e) {
            System.out.println("读取文件异常");
        }
        //获取key对应的value值
        String property = properties.getProperty(key);
        if (StringUtils.isBlank(property)) {
            property = StringPool.EMPTY;
        }
        return property;
    }
}
